﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;

using umbraco.BusinessLogic;
using umbraco.DataLayer;
using Umbraco.Core.Dynamics;
using Umbraco.Core.Models;
using Umbraco.Web;

namespace DAMP.PropertyEditorValueConverter
{
    public class DAMP_Item
    {
        private int? _id;
        private string _name;
        private string _type;
        private string _file;
        private string _alt;
        private string _resized;
        private DynamicXml _xml;
        private IPublishedContent _typedMedia;
        private dynamic _media;
        private DAMP_List _children;
        private Dictionary<string, string> _typedCrops;
        private DynamicDictionary _crops;
        private readonly XmlNode _xmlNode;

        private static ISqlHelper SqlHelper
        {
            get
            {
                return Application.SqlHelper;
            }
        }

        /// <summary>
        /// Returns the id of the media item.
        /// </summary>
        public int Id 
        { 
            get 
            {
                if (!_id.HasValue)
                {
                    _id = Convert.ToInt32(_xmlNode.Attributes["id"].Value);
                }
                return _id.Value;
            } 
        }

        /// <summary>
        /// Returns the name of the media item.
        /// </summary>
        public string Name
        {
            get
            {
                if (string.IsNullOrEmpty(_name))
                {
                    _name = _xmlNode.Attributes["nodeName"].Value;
                }
                return _name;
            }
        }

        /// <summary>
        /// Returns the media type of the media item.
        /// </summary>
        public string Type
        {
            get
            {
                if (string.IsNullOrEmpty(_type))
                {
                    _type = _xmlNode.Name;
                }

                return _type;
            }
        }

        /// <summary>
        /// Returns the umbracoFile property.
        /// </summary>
        public string File
        {
            get
            {
                if (string.IsNullOrEmpty(_file))
                {
                    _file = GetProperty("umbracoFile");
                }
                return _file;
            }
        }

        /// <summary>
        /// Returns the umbracoFile property.
        /// </summary>
        public string Url
        {
            get
            {
                return File;
            }
        }

        /// <summary>
        /// Returns the alt property. If it's empty it will return the name.
        /// </summary>
        public string Alt
        {
            get
            {
                if (string.IsNullOrEmpty(_alt))
                {
                    _alt = GetProperty("alt");

                    //If no property with the alt alias is found return the media item name.
                    if (string.IsNullOrEmpty(_alt))
                    {
                        _alt = Name;
                    }
                }

                return _alt;
            }
        }

        /// <summary>
        /// Returns the resized property.
        /// </summary>
        public string Resized
        {
            get
            {
                if (string.IsNullOrEmpty(_resized))
                {
                    _resized = GetProperty("resized");
                }
                return _resized;
            }
        }

        /// <summary>
        /// Returns this media item as DynamicXml.
        /// </summary>
        public DynamicXml Xml
        {
            get
            {
                if (_xml == null)
                {   
                    _xml = new DynamicXml(_xmlNode.OuterXml);
                }

                return _xml;
            }
        }

        /// <summary>
        /// Return this media item as TypedMedia.
        /// </summary>
        public IPublishedContent TypedMedia
        {
            get
            {
                if (_typedMedia == null)
                {
                    var umbHelper = new UmbracoHelper(UmbracoContext.Current);
                    _typedMedia = umbHelper.TypedMedia(Id);
                }

                return _typedMedia;
            }
        }

        /// <summary>
        /// Returns this media item as dynamic media.
        /// </summary>
        public dynamic Media
        {
            get
            {
                if (_media == null)
                {
                    var umbHelper = new UmbracoHelper(UmbracoContext.Current);
                    _media = umbHelper.Media(Id);
                }

                return _media;
            }
        }

        /// <summary>
        /// Returns the children of the current media item.
        /// </summary>
        public DAMP_List Children
        {
            get
            {
                if (_children == null)
                {
                    List<DAMP_Item> items = new List<DAMP_Item>();

                    //Find all media items that have the current media item as parent.
                    using (IRecordsReader dr = SqlHelper.ExecuteReader("Select id from umbracoNode where nodeObjectType = @type And parentId = @id order by sortOrder",
                        SqlHelper.CreateParameter("@type", umbraco.cms.businesslogic.media.Media._objectType),
                        SqlHelper.CreateParameter("@id", Id)))
                    {
                        while (dr.Read())
                        {
                            //Add the child media item to the list.
                            items.Add(new DAMP_Item(dr.GetInt("id")));
                        }
                    }

                    _children = new DAMP_List(items);
                }

                return _children;
            }
        }

        /// <summary>
        /// Returns the crops as a Dictionary<string, string> if dynamic isn't used.
        /// </summary>
        public Dictionary<string, string> TypedCrops
        {
            get
            {
                if (_typedCrops == null)
                {
                    _typedCrops = new Dictionary<string, string>();

                    foreach (XmlNode item in _xmlNode.SelectNodes("descendant::crop"))
                    {
                        //The DynamicDictionary only supports lowered keys.
                        _typedCrops.Add(item.Attributes["name"].Value.ToLower(), item.Attributes["url"].Value);
                    }
                }

                return _typedCrops;
            }
        }

        /// <summary>
        /// Returns the crops that are on this media item as a DynamicDictionary.
        /// <example>
        /// This example shows how to get a crop in Razor.
        /// <code>
        /// @item.Crops.widecrop
        /// </code>
        /// </example>
        /// </summary>
        public DynamicDictionary Crops
        {
            get
            {
                if (_crops == null)
                {
                    Dictionary<string, object> crops = new Dictionary<string, object>();

                    foreach (XmlNode item in _xmlNode.SelectNodes("descendant::crop"))
                    {
                        //The DynamicDictionary only supports lowered keys.
                        crops.Add(item.Attributes["name"].Value.ToLower(), item.Attributes["url"].Value);
                    }

                    _crops = new DynamicDictionary(crops);
                }

                return _crops;
            }
        }

        public DAMP_Item(int id)
        {
            var media = umbraco.library.GetMedia(id, false);
            _xmlNode = ((IHasXmlNode)media.Current).GetNode().FirstChild;
        }

        public DAMP_Item(XmlNode xml)
        {
            _xmlNode = xml;
        }

        /// <summary>
        /// Tries to get the property from this media item. If it's not found it returns an empty string.
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public string GetProperty(string name)
        {
            XmlNode node = _xmlNode.SelectSingleNode("descendant::" + name);
            if (node != null)
            {
                return node.InnerText;
            }

            return string.Empty;
        }
    }
}
